package com.et.core.goods

import android.content.Context
import android.database.ContentObserver
import android.database.Cursor
import android.net.Uri
import android.os.Handler
import android.util.Log
import androidx.annotation.IntDef
import androidx.recyclerview.widget.DiffUtil
import com.et.core.util.GoodsDiffCallBack

const val TAG = "core.goods provider"
const val AUTHORITY = "com.et.core.provider"
const val GOODS_TABLE_NAME = "table_channel"
val GOODS_URI: Uri = Uri.parse("content://$AUTHORITY/$GOODS_TABLE_NAME")

class GoodsProvider {

    companion object {
        @JvmStatic
        fun getInstance() = Holder.holder
    }

    object Holder {
        val holder = GoodsProvider()
    }

    private var export: ((r: DiffUtil.DiffResult, dest: MutableList<GoodsInfo>) -> Unit)? = null
    private var srcList: MutableList<GoodsInfo> = mutableListOf()
    private var observer: ContentObserver? = null
    fun observer(call: (r: DiffUtil.DiffResult, dest: MutableList<GoodsInfo>) -> Unit) {
        export = call
        Log.d(TAG, "refresh shop show list")
    }

    fun registerContentObserver(context: Context) {
        observer = object : ContentObserver(Handler()) {
            override fun onChange(selfChange: Boolean) {
                Log.d(TAG, "database has changed")
                val destList = getShowList(context)
                GoodsDiffCallBack(srcList, destList).let { callback ->
                    DiffUtil.calculateDiff(callback, true).also { result ->
                        export?.also { it ->
                            it(result, destList)
                        }
                        srcList = destList
                    }
                }
            }
        }
        context.contentResolver.registerContentObserver(
            GOODS_URI, true,
            observer as ContentObserver
        )
    }

    fun unregisterContentObserver(context: Context) {
        observer?.let { context.contentResolver.unregisterContentObserver(it) }
    }


    fun getChannelEntity(ctx: Context): MutableList<ChannelEntity> {
        val list = mutableListOf<ChannelEntity>()
        val cursor =
            ctx.contentResolver.query(GOODS_URI, null, null, null, null)?.also {
                if (it.moveToFirst()) {
                    do {
                        list.add(cursor2ChannelEntity(it))
                    } while (it.moveToNext())
                }
            }
        cursor?.close()
        return list
    }

    fun getShowList(ctx: Context): MutableList<GoodsInfo> {
        val destList = mutableListOf<GoodsInfo>()
        val cursor = ctx.contentResolver.query(GOODS_URI, null, null, null, null)?.also {
            if (it.moveToFirst()) {
                do {
                    if (it.getInt(it.getColumnIndex("status")) == ENABLED) {
                        destList.add(cursor2GoodsInfo(it))
                    }
                } while (it.moveToNext())
            }
        }
        cursor?.close()
        GoodsDiffCallBack(srcList, destList).let { callback ->
            DiffUtil.calculateDiff(callback, true).also { result ->
                export?.also { it ->
                    it(result, destList)
                }
                srcList = destList
            }
        }
        return destList
    }

    private fun cursor2GoodsInfo(cursor: Cursor): GoodsInfo {
        return GoodsInfo(
            barcode = cursor.getString(cursor.getColumnIndex("barcode")),
            name = cursor.getString(cursor.getColumnIndex("name")),
            image = cursor.getString(cursor.getColumnIndex("image_path_local")),
            discount = cursor.getInt(cursor.getColumnIndex("discount")),
            channel = GoodsInfo.Companion.Channel(
                box = cursor.getInt(cursor.getColumnIndex("box")),
                channel = cursor.getInt(cursor.getColumnIndex("channel")),
                price = cursor.getInt(cursor.getColumnIndex("price")),
                label = cursor.getString(cursor.getColumnIndex("label"))
            )

        )
    }

    private fun cursor2ChannelEntity(cursor: Cursor): ChannelEntity {
        val box = cursor.getInt(cursor.getColumnIndex("box"))
        val channel = cursor.getInt(cursor.getColumnIndex("channel"))
        return ChannelEntity.create(box = box, channel = channel).apply {
            this.label = cursor.getString(cursor.getColumnIndex("label"))
            this.priceCent = cursor.getInt(cursor.getColumnIndex("price"))
            this.status = cursor.getInt(cursor.getColumnIndex("status"))
            this.quantity = cursor.getInt(cursor.getColumnIndex("quantity"))
            this.barcode = cursor.getString(cursor.getColumnIndex("barcode"))
            this.name = cursor.getString(cursor.getColumnIndex("name"))
            this.image = cursor.getString(cursor.getColumnIndex("image_path_local"))
            this.discount = cursor.getInt(cursor.getColumnIndex("discount"))
        }
    }

}


@Retention(value = AnnotationRetention.SOURCE)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
@IntDef(UNDEFINE, ENABLED, DISABLED, LACK)
annotation class Status

const val UNDEFINE: Int = 0
const val ENABLED: Int = 1
const val DISABLED: Int = 2
const val LACK: Int = 3

data class ChannelEntity(
    var uid: Int = 0,
    var box: Int = 0,
    var channel: Int = 0,
    var label: String = "",
    var priceCent: Int = 0,
    @Status var status: Int = UNDEFINE,
    var quantity: Int = 0,
    var barcode: String = "${box}0$channel",
    var name: String = "UNDEFINE",
    var image: String = "",
    var discount: Int = 100,
    var sid: Int = 0
) {
//    fun setGoodsId(goodsId: Int) {
//        if (goodsId !in 0..256) return
//        status = status shr 8 shl 8 or goodsId
//    }
//
//
//    fun setGoodsCount(number: Int) {
//        if (number !in 0..20) return
//        status = (status and 0xff) or (number shl 8)
//    }

    companion object {
//        @Status
//        fun getState(status: Int): Int {
//            return when {
//                status == 0 -> UNDEFINE
//                getCount(status) == 0 -> {
//                    LACK
//                }
//                getGoodsId(status) == 0xEE -> {
//                    DISABLED
//                }
//                else -> ENABLED
//            }
//        }

//        fun getGoodsId(status: Int): Int {
//            return status shl 24 shr 24
//        }
//
//        fun getCount(status: Int): Int {
//            return status shr 8 and 0xff
//        }

        private fun uid(box: Int, channel: Int): Int = box * 1000 + channel

        fun label(box: Int, channel: Int): String {
            if (box == 11) return String.format("%02d", channel)
            if (box < 5) return String.format("%d%02d", box, channel)
            if (box < 10) return String.format("")
            return "$box$channel"
        }

        fun create(box: Int, channel: Int): ChannelEntity {
            return ChannelEntity(
                uid = uid(box, channel),
                box = box,
                channel = channel,
                label = label(box, channel),
                priceCent = 0,
                discount = 100,
                status = DISABLED,
                quantity = 0
            )
        }

        fun create(
            box: Int,
            channel: Int,
            priceCent: Int,
            barcode: String,
            discount: Int,
            @Status status: Int,
            quantity: Int,
            name: String
        ): ChannelEntity {
            return ChannelEntity(
                uid = uid(box, channel),
                box = box,
                channel = channel,
                label = label(box, channel),
                priceCent = priceCent,
                barcode = barcode,
                discount = discount,
                status = status,
                quantity = quantity,
                name = name
            )
        }
    }

    override fun toString(): String {
        return "ChannelEntity(uid=$uid, box=$box, channel=$channel, label='$label', priceCent=$priceCent, status=$status, quantity=$quantity, barcode='$barcode', name='$name', image='$image', discount=$discount, sid=$sid)"
    }
}